#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include "ATCSimulator.h"
#include "printing.h"
using namespace std;

vector<double> totalList;
void experimentOne();
void experimentTwo();

int main()
{
    experimentOne();
    //experimentTwo();
    return 0;
}

void experimentOne()
{
    int rewardStep = 11;
    int iterations = 50;


    ATCSimulator *simulator = new ATCSimulator(50,4, 5, 200);
    for(int z = 0; z < iterations; z++)
    {
        simulator->curTime = 0;
        vector<double> rewardList;
        vector<vector<pair<State*,Actions> > > stateActionPairsGlobal;
        while(!simulator->simulatorDone())
        {
            vector<pair<State*,Actions> > stateActionPairs;
            for(unsigned int i = 0; i < simulator->airplanes.size(); i++)
            {
                //Get the current Airplane/Airport
                Airplane curAirplane = simulator->airplanes[i];
                Airport curAirport = simulator->airports[curAirplane.currentAirport];
                if(curAirplane.state == TRAVELING || curAirplane.state == LANDED) continue;
                //Get the state of the airplane
                State* state = simulator->getState(curAirplane);
                //Find all actions that can be done to airplane.
                vector<int> possibleActions = curAirplane.getActions(simulator->airports, simulator->lookupTable);
                //Ask the airport/agent which action to take.
                Actions a = curAirport.getAction(state, possibleActions);
                //Actions a = RouteFirst;
                //Update airplane variables based on action taken.
                simulator->airplanes[i].takeAction(a, simulator->lookupTable);
                //Update edge departure lists.
                simulator->updateEdges(curAirplane);
                stateActionPairs.push_back(make_pair(state, a));
            }
            stateActionPairsGlobal.push_back(stateActionPairs);

            //Update simulator
            simulator->update();
            //Get a reward
            double reward = simulator->getReward();
            rewardList.push_back(reward);
            if(stateActionPairsGlobal.size() >= (unsigned int)rewardStep*2)
            {
                int updateTime = simulator->curTime - rewardStep*2;
                //Update Agents with reward
                simulator->updateAgents(rewardList, stateActionPairsGlobal[updateTime], updateTime, rewardStep);
            }
        }
        double total = 0;
        for(unsigned int i = 0; i < rewardList.size(); i++)
        {
            total+=rewardList[i];
        }
        totalList.push_back(total);
        printf("%f \n", total);
        simulator->resetSimulation(20);
    }
    printcsv(totalList, "Experiment1");
}

void experimentTwo()
{

    int iterations = 50;
    int rewardStep = 11;

    ATCSimulator *simulator = new ATCSimulator(20,3, 10, 100);
    for(int z = 0; z < iterations; z++)
    {
        simulator->curTime = 0;
        vector<double> rewardList;
        vector<vector<dataStruct> > stateActionPairsGlobal;
        vector<vector<pair<State*,Actions> > > stateActionPairsGlobalSecondary;
        while(!simulator->simulatorDone())
        {
            vector<dataStruct> stateActionPairs;
            vector<pair<State*,Actions> > stateActionPairsSecondary;
            for(unsigned int i = 0; i < simulator->airplanes.size(); i++)
            {
                Airplane* curAirplane = &simulator->airplanes[i];
                Airport curAirport = simulator->airports[curAirplane->currentAirport];
                if(curAirplane->state == TRAVELING || curAirplane->state == LANDED) continue;
                //Get the state of the airplane
                State* state = simulator->getState(*curAirplane);
                //Find all actions that can be done to airplane.
                vector<int> possibleActions = curAirplane->getActions(simulator->airports, simulator->lookupTable);
                //Ask the airport/agent which action to take.
                Actions a = curAirport.getAction(state, possibleActions);
                //Actions a = RouteFirst;
                //Update airplane variables based on action taken.
                 if(curAirplane->prevState != 0)
                {
                    dataStruct ds;
                    ds.prevState = curAirplane->prevState;
                    ds.prevAction = curAirplane->prevAction;
                    ds.state = state;
                    ds.action = a;
                    ds.airportNum = curAirport.airportNum;
                    stateActionPairs.push_back(ds);
                    curAirplane->oneStop = false;
                }
                //Remember the previous actions
                curAirplane->prevAction = a;
                curAirplane->prevState = state;
                simulator->airplanes[i].takeAction(a, simulator->lookupTable);
                simulator->updateEdges(*curAirplane);
            }
            //If the plane only had one stop, fill in the secondary stateAction pairs for future updating w/o
            //a next state.
            for(unsigned int i = 0; i < simulator->airplanes.size(); i++)
            {
                if(simulator->airplanes[i].state == LANDED && simulator->airplanes[i].oneStop == true)
                {
                    State* state = simulator->airplanes[i].prevState;
                    Actions a = simulator->airplanes[i].prevAction;
                    stateActionPairsGlobalSecondary[simulator->curTime - simulator->airplanes[i].edgeLoc - 1].push_back(make_pair(state, a));
                    simulator->airplanes[i].oneStop = false;
                }
            }
            stateActionPairsGlobal.push_back(stateActionPairs);
            stateActionPairsGlobalSecondary.push_back(stateActionPairsSecondary);
            //Update simulator
            simulator->update();
            //Get a reward
            double reward = simulator->getReward();
            rewardList.push_back(reward);

            //Update Agents with reward
            if(stateActionPairsGlobal.size() >= (unsigned int)rewardStep*2)
            {
                int updateTime = simulator->curTime - rewardStep*2;
                simulator->updateAgents(rewardList, stateActionPairsGlobal[updateTime], updateTime, rewardStep);
                simulator->updateAgents(rewardList, stateActionPairsGlobalSecondary[updateTime], updateTime, rewardStep);
            }
        }
        double total = 0;
        for(unsigned int i = 0; i < rewardList.size(); i++)
        {
            total+=rewardList[i];
        }
        printf("%f \n", total);
        totalList.push_back(total);
        simulator->resetSimulation(20);
    }
    printcsv(totalList, "Experiment2-2");
}
